/**
    ******************************************************************************
    * @file    main.c 
    * @author  18408107475@163.com
    * @version v1.0
    * @date    2025/03/31
    * @brief   基于STM32F10x的LED与蜂鸣器控制系统
    * @details 
    * 功能特性：
    * - 双LED交替闪烁控制（PB5/PE5）
    * - 蜂鸣器基础控制（PB8）
    * - 定时器TIM6中断实现1秒周期
    * - 三级延时函数（微秒/毫秒/秒）
    * 
    * 硬件连接：
    * - PB5: LED1（低电平点亮）
    * - PE5: LED2（低电平点亮）
    * - PB8: 有源蜂鸣器（高电平触发）
    * 
    * 注意事项：
    * 1. 当前系统时钟默认使用HSI 8MHz，需配置为72MHz保证定时准确
    * 2. 中断服务程序中应避免使用阻塞延时函数
    ******************************************************************************
**/

/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f10x.h"  // STM32标准外设库，包含所有外设寄存器定义

/* 函数声明 ------------------------------------------------------------------*/
void LED_STD_Config(void);     // LED GPIO初始化
void BEEP_STD_Config(void);    // 蜂鸣器GPIO初始化
void TIM6_CONFIG(void);        // TIM6定时器配置
void Delay_us(uint32_t xms);   // 微秒延时
void Delay_ms(uint32_t xms);   // 毫秒延时
void Delay_s(uint32_t xms);    // 秒延时

/* 全局变量 ------------------------------------------------------------------*/
volatile uint8_t led_toggle_flag = 0; // LED状态切换标志（改进建议使用）

/**
    ******************************************************************************
    * @brief  LED GPIO初始化
    * @param  无
    * @retval 无
    * @detail 配置PB5和PE5为推挽输出模式
    * 硬件连接：
    * - PB5连接LED1，低电平点亮
    * - PE5连接LED2，低电平点亮
    * 初始状态：
    * - LED1熄灭（PB5高电平）
    * - LED2点亮（PE5低电平）
    ******************************************************************************
**/
void LED_STD_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    /* 开启GPIOB和GPIOE时钟（APB2总线） */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);

    /* 配置PB5引脚 */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  // 高速模式可改善边沿特性
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;  // 推挽输出直接驱动LED
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* 配置PE5引脚（复用同一结构体） */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init(GPIOE, &GPIO_InitStructure);

    /* 设置初始状态 */
    GPIO_SetBits(GPIOB, GPIO_Pin_5);   // LED1初始熄灭
    GPIO_ResetBits(GPIOE, GPIO_Pin_5); // LED2初始点亮
}

/**
    ******************************************************************************
    * @brief  蜂鸣器初始化
    * @param  无
    * @retval 无
    * @detail 配置PB8为推挽输出，控制有源蜂鸣器
    * 注意：
    * - 适用于3.3V有源蜂鸣器，高电平触发
    * - 驱动无源蜂鸣器需改用PWM输出模式
    ******************************************************************************
**/
void BEEP_STD_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_8;
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;    // 推挽输出
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;    // 高速模式确保快速响应
    GPIO_SetBits(GPIOB, GPIO_Pin_8);
    Delay_ms(100);
    GPIO_ResetBits(GPIOB, GPIO_Pin_8);  // 初始状态关闭蜂鸣器
}

/**
	******************************************************************************
	* @brief  微秒级延时
	* @param  xus 延时时长，范围：0 ~ 1864134 us
	* @note   选择外部时钟STCLK —— 9MHz
	* @retval 无
	* @detail 工作原理：
	*   - SysTick为24位递减计数器
	*   - 计算公式：LOAD = (时钟频率/1000000) * xus - 1
	*   - 9MHz时钟时，1us需要9个时钟周期
	* 注意事项：
	*   - 最大延时受24位计数器限制
	*   - 不适用于在中断中调用
	******************************************************************************
*/
void Delay_us(uint32_t xus)
{
    SysTick->CTRL = 0;                      // 关闭SysTick
    SysTick->LOAD = (9 * xus) - 1;          // 设置重装载值(9MHz时钟下)
    SysTick->VAL = 0x00;                    // 清除当前值
    SysTick->CTRL = 0x00000001;             // 启用SysTick（使用STCLK）
    while(!(SysTick->CTRL & 0x00010000));   // 等待COUNTFLAG置位
    SysTick->CTRL = 0;                      // 关闭SysTick
}

/**
	******************************************************************************
	* @brief  毫秒级延时
	* @param  xms 延时时长，范围：0~1864 ms
	* @note   基于Delay_us实现
	* @retval 无
	* 注意事项：
	*   - 实际最大延时受Delay_us限制
	*   - 存在函数调用开销，精度略低于直接使用SysTick
	******************************************************************************
*/
void Delay_ms(uint32_t xms)
{
    while(xms--)
    {
        Delay_us(1000);  // 累计延时
    }
}

/**
	******************************************************************************
	* @brief  秒级延时
	* @param  xs 延时时长，范围：0~1 s
	* @note   基于Delay_ms实现
	* @retval 无
	* 注意事项：
	*   - 适用于非精确长延时
	*   - 长时间阻塞式延时影响系统实时性
	******************************************************************************
*/
void Delay_s(uint32_t xs)
{
    while(xs--)
    {
        Delay_ms(1000);  // 累计延时
    }
} 


/**
    ******************************************************************************
    * @brief  TIM6中断服务程序（存在设计问题）
    * @detail 当前实现问题：
    * 1. 使用阻塞式Delay_s()导致系统无法响应其他中断
    * 2. LED切换逻辑错误（交替周期实际为2秒）
    * 3. 未考虑重入问题（虽然TIM6中断间隔足够长）
    * 建议改进方案见代码下方
    ******************************************************************************
**/
void TIM6_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM6, TIM_IT_Update))
    {
        /* 问题代码段 - 阻塞式延时 */
        GPIO_SetBits(GPIOB, GPIO_Pin_5);   // LED1灭
		Delay_ms(500);
        GPIO_ResetBits(GPIOE, GPIO_Pin_5); // LED2亮
        Delay_ms(500);
        GPIO_SetBits(GPIOE, GPIO_Pin_5);
		Delay_ms(500);
        GPIO_ResetBits(GPIOB, GPIO_Pin_5);
		Delay_ms(500);
        
        TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
    }
}

/**
    ******************************************************************************
    * @brief  TIM6定时器配置
    * @param  无
    * @retval 无
    * @detail 配置TIM6为1秒周期中断
    * 参数计算（假设系统时钟72MHz）：
    * 预分频值 = 7200-1 → 72MHz/7200 = 10kHz
    * 自动重载值 = 10000-1 → 10kHz/10000 = 1Hz
    * 问题：
    * - 未配置系统时钟，默认HSI 8MHz会导致定时不准确
    * - 中断优先级设为最高可能影响其他中断
    ******************************************************************************
**/
void TIM6_CONFIG(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
    
    TIM_TimeBaseStructure.TIM_Prescaler = 7200-1;    // 预分频器
    TIM_TimeBaseStructure.TIM_Period = 10000-1;       // 自动重载值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);

    TIM_ClearFlag(TIM6, TIM_FLAG_Update);  // 清除初始更新标志
    
    /* 中断优先级配置（建议降低优先级） */
    NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 改为非0优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM6, ENABLE);
}

/**
    ******************************************************************************
    * @brief  系统时钟配置（缺失的重要功能）
    * @detail 建议添加以下配置：
    * 1. 启用外部晶振（HSE）
    * 2. 配置PLL输出72MHz
    * 3. 切换系统时钟到PLL
    * 此函数未在main中调用是当前重大缺陷
    ******************************************************************************
**/
void SystemClock_Config(void)
{
    // 示例配置代码（需要根据实际硬件补充）
    RCC_DeInit();
    RCC_HSEConfig(RCC_HSE_ON);
    if(RCC_WaitForHSEStartUp() == SUCCESS) {
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
        RCC_PLLCmd(ENABLE);
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        while(RCC_GetSYSCLKSource() != 0x08);
    }
}

/**
    ******************************************************************************
    * @brief  主函数
    * @detail 主要问题：
    * 1. 未初始化系统时钟
    * 2. 主循环无任务处理
    * 建议改进：
    * - 添加看门狗支持
    * - 实现低功耗模式
    * - 处理中断产生的标志位
    ******************************************************************************
**/
int main(void)
{
    // SystemClock_Config();  // 必须添加！！！
    LED_STD_Config();
    BEEP_STD_Config();
    TIM6_CONFIG();

    while(1)
    {
        /* 改进建议 */
        // if(led_toggle_flag) { ... }  // 处理中断标志
        // __WFI();  // 进入睡眠模式
    }
}

/*************************************END OF FILE**************************************/